package com.net.lnk.batch.bank;

import javax.sql.DataSource;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.launch.support.SimpleJobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.batch.support.DatabaseType;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.StringUtils;

import com.net.lnk.batch.bank.batch.BankcardImportJobListener;
import com.net.lnk.batch.bank.batch.BankcardItemProcessor;
import com.net.lnk.batch.bank.batch.BankcardItemWriter;
import com.net.lnk.batch.bank.dto.BankcardDTO;
import com.net.lnk.batch.bank.model.BankcardModel;

@SpringBootApplication
@MapperScan({ "com.net.lnk.batch.bank.dao" })
@EnableBatchProcessing
public class BatchBankApplication {

	public static void main(String[] args) {
		SpringApplication.run(BatchBankApplication.class, args);
	}

	@Bean
	public JobRepository jobRepository(DataSource dataSource, PlatformTransactionManager transactionManager)
			throws Exception {

		JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();
		jobRepositoryFactoryBean.setDataSource(dataSource);
		jobRepositoryFactoryBean.setTransactionManager(transactionManager);
		jobRepositoryFactoryBean.setDatabaseType(DatabaseType.MYSQL.name());

		return jobRepositoryFactoryBean.getObject();
	}

	@Bean
	public SimpleJobLauncher jobLauncher(DataSource dataSource, PlatformTransactionManager transactionManager)
			throws Exception {

		SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
		jobLauncher.setJobRepository(jobRepository(dataSource, transactionManager));

		return jobLauncher;
	}

	@Bean
	public BankcardImportJobListener bankcardImportJobListener() {
		return new BankcardImportJobListener();
	}

	@Bean
	public Job importJob(JobBuilderFactory jobs, Step step) {
		return jobs.get("importBankcardJob").incrementer(new RunIdIncrementer()).flow(step) // 为Job指定Step
				.end().listener(bankcardImportJobListener()) // 绑定监听器
				.build();
	}

	@Bean
	@StepScope
	public FlatFileItemReader<BankcardDTO> bankcardItemReader(
			@Value("#{jobParameters['input.file.name']}") String filePath) {
		// 使用FlatFileItemReader读取文件
		FlatFileItemReader<BankcardDTO> reader = new FlatFileItemReader<BankcardDTO>();
		if (StringUtils.isEmpty(filePath)) {
			reader.setResource(new ClassPathResource("bankcard.csv"));
		} else {
			reader.setResource(new ClassPathResource(filePath));
		}

		DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();
		tokenizer.setNames(new String[] { "bankName", "cardName", "cardNoLength", "cardNoSample", "binLength", "bin",
				"cardType" });

		BeanWrapperFieldSetMapper<BankcardDTO> fieldSetMapper = new BeanWrapperFieldSetMapper<BankcardDTO>();
		fieldSetMapper.setTargetType(BankcardDTO.class);

		DefaultLineMapper<BankcardDTO> lineMapper = new DefaultLineMapper<BankcardDTO>();
		lineMapper.setLineTokenizer(tokenizer);
		lineMapper.setFieldSetMapper(fieldSetMapper);

		reader.setLineMapper(lineMapper);
		return reader;
	}

	@Bean
	public ItemProcessor<BankcardDTO, BankcardModel> bankcardItemProcessor() {
		BankcardItemProcessor processor = new BankcardItemProcessor();
		return processor;
	}

	@Bean
	public ItemWriter<BankcardModel> bankcardItemWriter() {
		return new BankcardItemWriter();
	}

	@Bean
	public Step bankcardImportStep(StepBuilderFactory stepBuilderFactory, ItemReader<BankcardDTO> reader,
			ItemProcessor<BankcardDTO, BankcardModel> processor, ItemWriter<BankcardModel> writer) {
		return stepBuilderFactory.get("bankcardImportStep").<BankcardDTO, BankcardModel>chunk(200) // 批处理每次提交200条数据
				.reader(reader) // 给step绑定reader
				.processor(processor) // 给step绑定processor
				.writer(writer) // 给step绑定writer
				.build();
	}

}
